package com.guofs.project.common.utils.tree.util.impl;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Multimap;
import com.guofs.project.common.utils.function.BiPredicate;
import com.guofs.project.common.utils.tree.BaseNodeModelTree;
import com.guofs.project.common.utils.tree.base.TreeBase;
import com.guofs.project.common.utils.tree.util.TreeUtils;

import java.util.Map;

/**
 * 基于BaseNodeModelTree的树工具集的实现
 * @author 郭芳诗
 * @date 2019/1/21 10:47
 */
public class NodeModelTreeUtil<N, K> implements TreeUtils<N, K> {

    /**
     * 将两个树的数据进行匹配
     *
     * @param nTree     第一个树的节点
     * @param oTree     另一个树的节点
     * @param predicate 匹配条件
     * @param rootIgnoreFlag 树根节点跳过匹配，true为跳过
     * @return 匹配后的结果, 对照表，入参前者对后者
     */
    @Override
    public BiMap<K, K> match(TreeBase<N, K> nTree,
                             TreeBase<N, K> oTree,
                             BiPredicate<N, N> predicate,
                             boolean rootIgnoreFlag) {
        BaseNodeModelTree<N, K> bnNTree = null;
        BaseNodeModelTree<N, K> bnOTree = null;
        if (nTree instanceof BaseNodeModelTree) {
            bnNTree = (BaseNodeModelTree<N, K>) nTree;
        } else {
            throw new NullPointerException("传入参数类型不对，请检查是否是这个类型：" + BaseNodeModelTree.class.getSimpleName());
        }
        if (oTree instanceof BaseNodeModelTree) {
            bnOTree = (BaseNodeModelTree<N, K>) oTree;
        } else {
            throw new NullPointerException("传入参数类型不对，请检查是否是这个类型：" + BaseNodeModelTree.class.getSimpleName());
        }
        BiMap<K, K> keyMap = HashBiMap.create();

        // 用于获取其下子节点数据的树
        Multimap<K, K> nextKeyMap = ArrayListMultimap.create();

        for (N nObj: bnNTree.getRoot()) {
            for (N oObj: bnOTree.getRoot()) {
                K bnK = bnNTree.getKey(nObj);
                K boK = bnOTree.getKey(oObj);
                // 树根节点是否匹配
                if (rootIgnoreFlag) {
                    if (!nextKeyMap.containsEntry(bnK, boK)) {
                        nextKeyMap.put(bnK, boK);
                    }
                    // 跳过匹配
                    continue;
                }
                // 匹配树根上的数据
                if (predicate.apply(nObj, oObj)) {
                    keyMap.put(bnK, boK);
                    if (!nextKeyMap.containsEntry(bnK, boK)) {
                        nextKeyMap.put(bnK, boK);
                    }
                }
            }
        }

        // 计数跳出
        int jump = bnNTree.getRoot().size();
        Multimap<K, K> nextKeyMapTemp = ArrayListMultimap.create();

        while (jump < bnNTree.findAll().size()) {
            nextKeyMapTemp.putAll(nextKeyMap);
            nextKeyMap.clear();

            for (Map.Entry<K, K> emp: nextKeyMapTemp.entries()) {
                for (N nObj: bnNTree.getChildren(emp.getKey())) {
                    for (N oObj: bnOTree.getChildren(emp.getValue())) {
                        // 匹配树根上的数据
                        if (predicate.apply(nObj, oObj)) {
                            K bnK = bnNTree.getKey(nObj);
                            K boK = bnOTree.getKey(oObj);

                            keyMap.put(bnK, boK);
                            if (!nextKeyMap.containsEntry(bnK, boK)) {
                                nextKeyMap.put(bnK, boK);
                            }
                        }
                    }
                    jump++;
                }
            }

            nextKeyMapTemp.clear();
        }

        return keyMap;
    }

}
